/**
 * API稳定性增强测试脚本
 * 用于测试API在高并发情况下的稳定性、错误处理机制和响应格式一致性
 */

const http = require('http')
const { performance } = require('perf_hooks')
const fs = require('fs')
const path = require('path')

// 配置
const config = {
  host: 'localhost',
  port: 7204,
  endpoints: [
    {
      path: '/api/config',
      method: 'GET',
      expectedFormat: { minTitle: 'string', title: 'string' },
    },
    {
      path: '/api/typewriter-texts',
      method: 'GET',
      expectedFormat: { data: 'array', total: 'number', code: 'number' },
    },
    {
      path: '/api/projects?limit=10&page=1',
      method: 'GET',
      expectedFormat: {
        data: 'array',
        total: 'number',
        code: 'number',
        page: 'number',
        limit: 'number',
      },
    },
    {
      path: '/api/blogs?limit=10&page=1',
      method: 'GET',
      expectedFormat: {
        data: 'array',
        total: 'number',
        code: 'number',
        limit: 'number',
        page: 'number',
      },
    },
    {
      path: '/api/tech-stack',
      method: 'GET',
      expectedFormat: { data: 'array', code: 'number' },
    },
    {
      path: '/health',
      method: 'GET',
      expectedFormat: {
        status: 'string',
        timestamp: 'string',
        server: 'object',
        process: 'object',
        database: 'object',
      },
    },
  ],
  errorTests: [
    { path: '/api/nonexistent', method: 'GET', expectedStatus: 404 },
    { path: '/api/projects?limit=invalid', method: 'GET', expectedStatus: 400 },
    { path: '/api/blog/999999', method: 'GET', expectedStatus: 404 },
  ],
  concurrentRequests: 20, // 并发请求数
  rounds: 3, // 测试轮数
  delayBetweenRounds: 2000, // 轮次间隔（毫秒）
  outputFile: 'test-results.json', // 测试结果输出文件
}

// 检查服务器是否在运行
async function checkServerRunning() {
  return new Promise((resolve) => {
    const req = http.request(
      {
        hostname: config.host,
        port: config.port,
        path: '/health',
        method: 'GET',
        timeout: 2000,
      },
      () => {
        resolve(true)
      },
    )

    req.on('error', () => {
      resolve(false)
    })

    req.on('timeout', () => {
      req.destroy()
      resolve(false)
    })

    req.end()
  })
}

// 发送单个请求
function sendRequest(endpoint) {
  return new Promise((resolve) => {
    const startTime = performance.now()

    const options = {
      hostname: config.host,
      port: config.port,
      path: endpoint.path,
      method: endpoint.method,
      headers: {
        Accept: 'application/json',
      },
      timeout: 5000, // 添加超时设置
    }

    const req = http.request(options, (res) => {
      const endTime = performance.now()
      const duration = endTime - startTime

      let data = ''

      res.on('data', (chunk) => {
        data += chunk
      })

      res.on('end', () => {
        let parsedData = null
        let formatValid = false

        try {
          if (data) {
            parsedData = JSON.parse(data)

            // 验证响应格式
            if (endpoint.expectedFormat) {
              formatValid = validateResponseFormat(
                parsedData,
                endpoint.expectedFormat,
              )
            } else {
              formatValid = true
            }
          }
        } catch (e) {
          console.error(`解析响应数据失败: ${e.message}`)
        }

        resolve({
          endpoint: endpoint.path,
          statusCode: res.statusCode,
          duration: duration.toFixed(2),
          headers: res.headers,
          success: res.statusCode >= 200 && res.statusCode < 300,
          formatValid: formatValid,
          data: parsedData,
          expectedStatus: endpoint.expectedStatus,
          statusValid: endpoint.expectedStatus
            ? res.statusCode === endpoint.expectedStatus
            : true,
        })
      })
    })

    req.on('error', (error) => {
      const endTime = performance.now()
      const duration = endTime - startTime

      resolve({
        endpoint: endpoint.path,
        error: error.message,
        duration: duration.toFixed(2),
        success: false,
        formatValid: false,
        connectionError: true,
      })
    })

    req.on('timeout', () => {
      req.destroy()
      const endTime = performance.now()
      const duration = endTime - startTime

      resolve({
        endpoint: endpoint.path,
        error: '请求超时',
        duration: duration.toFixed(2),
        success: false,
        formatValid: false,
        timeout: true,
      })
    })

    req.end()
  })
}

// 验证响应格式
function validateResponseFormat(data, expectedFormat) {
  if (!data || typeof data !== 'object') return false

  for (const [key, expectedType] of Object.entries(expectedFormat)) {
    // 检查键是否存在
    if (!(key in data)) {
      console.error(`格式验证失败: 缺少键 "${key}"`)
      return false
    }

    // 检查类型是否匹配
    const actualType = Array.isArray(data[key]) ? 'array' : typeof data[key]
    if (actualType !== expectedType) {
      console.error(
        `格式验证失败: 键 "${key}" 的类型应为 "${expectedType}", 实际为 "${actualType}"`,
      )
      return false
    }
  }

  return true
}

// 发送并发请求
async function sendConcurrentRequests(endpoint, count) {
  const promises = []

  for (let i = 0; i < count; i++) {
    promises.push(sendRequest(endpoint))
  }

  try {
    const results = await Promise.all(promises)
    return results
  } catch (error) {
    console.error('并发请求失败:', error)
    return []
  }
}

// 运行测试
async function runTest() {
  console.log('开始API稳定性测试...')

  // 检查服务器是否运行
  const serverRunning = await checkServerRunning()
  if (!serverRunning) {
    console.error(
      '错误: 无法连接到服务器。请确保服务器正在运行，端口为',
      config.port,
    )
    console.log('创建模拟测试结果...')

    // 创建模拟测试结果
    const mockResults = {
      timestamp: new Date().toISOString(),
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      averageDuration: 0,
      totalDuration: 0,
      statusCodes: {},
      formatValidation: {
        valid: 0,
        invalid: 0,
      },
      errorHandling: {
        valid: 0,
        invalid: 0,
      },
      endpointResults: {},
      serverStatus: 'offline',
    }

    // 保存模拟测试结果
    fs.writeFileSync(
      path.join(__dirname, config.outputFile),
      JSON.stringify(mockResults, null, 2),
      'utf8',
    )

    console.log(`测试结果已保存到 ${config.outputFile}`)
    return mockResults
  }

  console.log(`并发请求数: ${config.concurrentRequests}`)
  console.log(`测试轮数: ${config.rounds}`)
  console.log('-----------------------------------')

  const summary = {
    timestamp: new Date().toISOString(),
    totalRequests: 0,
    successfulRequests: 0,
    failedRequests: 0,
    averageDuration: 0,
    totalDuration: 0,
    statusCodes: {},
    formatValidation: {
      valid: 0,
      invalid: 0,
    },
    errorHandling: {
      valid: 0,
      invalid: 0,
    },
    endpointResults: {},
    serverStatus: 'online',
  }

  // 1. 测试正常端点
  for (let round = 1; round <= config.rounds; round++) {
    console.log(`\n开始第 ${round} 轮测试 - 正常端点`)

    for (const endpoint of config.endpoints) {
      console.log(`\n测试端点: ${endpoint.path}`)

      try {
        const results = await sendConcurrentRequests(
          endpoint,
          config.concurrentRequests,
        )

        let roundSuccess = 0
        let roundFailed = 0
        let roundTotalDuration = 0
        let formatValid = 0
        let formatInvalid = 0
        let connectionErrors = 0

        for (const result of results) {
          summary.totalRequests++

          if (result.connectionError) {
            connectionErrors++
            summary.failedRequests++
            roundFailed++
            continue
          }

          roundTotalDuration += parseFloat(result.duration)

          if (result.success) {
            summary.successfulRequests++
            roundSuccess++
          } else {
            summary.failedRequests++
            roundFailed++
          }

          // 记录状态码
          const statusCode = result.statusCode || 'error'
          summary.statusCodes[statusCode] =
            (summary.statusCodes[statusCode] || 0) + 1

          // 记录格式验证结果
          if (result.formatValid) {
            summary.formatValidation.valid++
            formatValid++
          } else {
            summary.formatValidation.invalid++
            formatInvalid++
          }
        }

        summary.totalDuration += roundTotalDuration

        // 记录端点结果
        if (!summary.endpointResults[endpoint.path]) {
          summary.endpointResults[endpoint.path] = {
            success: 0,
            failed: 0,
            formatValid: 0,
            formatInvalid: 0,
            averageDuration: 0,
            totalRequests: 0,
            connectionErrors: 0,
          }
        }

        summary.endpointResults[endpoint.path].success += roundSuccess
        summary.endpointResults[endpoint.path].failed += roundFailed
        summary.endpointResults[endpoint.path].formatValid += formatValid
        summary.endpointResults[endpoint.path].formatInvalid += formatInvalid
        summary.endpointResults[endpoint.path].totalRequests += results.length
        summary.endpointResults[endpoint.path].connectionErrors +=
          connectionErrors

        if (results.length - connectionErrors > 0) {
          const avgDuration =
            roundTotalDuration / (results.length - connectionErrors)
          if (round === 1) {
            summary.endpointResults[endpoint.path].averageDuration =
              avgDuration
          } else {
            summary.endpointResults[endpoint.path].averageDuration =
              (summary.endpointResults[endpoint.path].averageDuration *
                (round - 1) +
                avgDuration) /
              round
          }
        }

        console.log(
          `成功: ${roundSuccess}, 失败: ${roundFailed}, 连接错误: ${connectionErrors}, 格式有效: ${formatValid}, 格式无效: ${formatInvalid}`,
        )
        if (results.length - connectionErrors > 0) {
          console.log(
            `平均响应时间: ${(roundTotalDuration / (results.length - connectionErrors)).toFixed(2)} ms`,
          )
        } else {
          console.log('平均响应时间: N/A (所有请求都失败)')
        }
      } catch (error) {
        console.error(`测试端点 ${endpoint.path} 失败:`, error)
      }
    }

    if (round < config.rounds) {
      console.log(
        `\n等待 ${config.delayBetweenRounds / 1000} 秒后开始下一轮测试...`,
      )
      await new Promise((resolve) =>
        setTimeout(resolve, config.delayBetweenRounds),
      )
    }
  }

  // 2. 测试错误处理
  console.log('\n开始错误处理测试')

  for (const errorTest of config.errorTests) {
    console.log(
      `\n测试错误端点: ${errorTest.path} (期望状态码: ${errorTest.expectedStatus})`,
    )

    try {
      const results = await sendConcurrentRequests(
        errorTest,
        Math.ceil(config.concurrentRequests / 2),
      )

      let statusValid = 0
      let statusInvalid = 0
      let connectionErrors = 0

      for (const result of results) {
        summary.totalRequests++

        if (result.connectionError) {
          connectionErrors++
          continue
        }

        // 记录状态码
        const statusCode = result.statusCode || 'error'
        summary.statusCodes[statusCode] =
          (summary.statusCodes[statusCode] || 0) + 1

        // 验证状态码是否符合预期
        if (result.statusValid) {
          summary.errorHandling.valid++
          statusValid++
        } else {
          summary.errorHandling.invalid++
          statusInvalid++
        }
      }

      console.log(
        `状态码符合预期: ${statusValid}, 状态码不符合预期: ${statusInvalid}, 连接错误: ${connectionErrors}`,
      )
    } catch (error) {
      console.error(`测试错误端点 ${errorTest.path} 失败:`, error)
    }
  }

  // 计算平均响应时间
  const successfulRequests = summary.totalRequests - summary.failedRequests
  if (successfulRequests > 0) {
    summary.averageDuration = summary.totalDuration / successfulRequests
  }

  // 打印总结
  console.log('\n-----------------------------------')
  console.log('测试总结:')
  console.log(`总请求数: ${summary.totalRequests}`)
  console.log(`成功请求数: ${summary.successfulRequests}`)
  console.log(`失败请求数: ${summary.failedRequests}`)

  if (summary.totalRequests > 0) {
    console.log(
      `成功率: ${((summary.successfulRequests / summary.totalRequests) * 100).toFixed(2)}%`,
    )
  } else {
    console.log('成功率: N/A (无请求)')
  }

  if (successfulRequests > 0) {
    console.log(`平均响应时间: ${summary.averageDuration.toFixed(2)} ms`)
  } else {
    console.log('平均响应时间: N/A (无成功请求)')
  }

  const totalFormatValidations =
    summary.formatValidation.valid + summary.formatValidation.invalid
  console.log('\n格式验证:')
  console.log(`有效格式: ${summary.formatValidation.valid}`)
  console.log(`无效格式: ${summary.formatValidation.invalid}`)

  if (totalFormatValidations > 0) {
    console.log(
      `格式有效率: ${((summary.formatValidation.valid / totalFormatValidations) * 100).toFixed(2)}%`,
    )
  } else {
    console.log('格式有效率: N/A (无格式验证)')
  }

  const totalErrorHandlings =
    summary.errorHandling.valid + summary.errorHandling.invalid
  console.log('\n错误处理:')
  console.log(`正确处理: ${summary.errorHandling.valid}`)
  console.log(`错误处理: ${summary.errorHandling.invalid}`)

  if (totalErrorHandlings > 0) {
    console.log(
      `错误处理正确率: ${((summary.errorHandling.valid / totalErrorHandlings) * 100).toFixed(2)}%`,
    )
  } else {
    console.log('错误处理正确率: N/A (无错误处理)')
  }

  console.log('\n状态码分布:')
  for (const statusCode in summary.statusCodes) {
    console.log(`${statusCode}: ${summary.statusCodes[statusCode]} 次`)
  }

  // 保存测试结果
  try {
    fs.writeFileSync(
      path.join(__dirname, config.outputFile),
      JSON.stringify(summary, null, 2),
      'utf8',
    )
    console.log(`\n测试结果已保存到 ${config.outputFile}`)
  } catch (error) {
    console.error('保存测试结果失败:', error)
  }

  return summary
}

// 运行测试
runTest().catch((error) => {
  console.error('测试执行失败:', error)
})
